<?php
error_reporting(E_ALL);
/**
 * DpContext Class.
 * Singleton resource for
 * session level information.
 *
 *  A session is only possible when logged in.
 *  Logging in requires a database.
 */

//require_once "DpPhpbb3.class.php";
//require_once "DpProject.class.php";
//require_once "DpPage.class.php";
//require_once "rounds.php";
//require_once DP_URL."/pinc/lists.php";
//require_once $relPath."lists.php";

define("PG_EVT_ADD",                  "add");
define("PG_EVT_REPLACE_TEXT",         "replace_text");
define("PG_EVT_REPLACE_IMAGE",        "replace_image");
define("PG_EVT_REPLACE_BOTH",         "replace_both");
define("PG_EVT_SAVE_TEMP",            "save_temp");
define("PG_EVT_RESUME",               "resume");
define("PG_EVT_SAVE_DONE",            "save_done");
define("PG_EVT_REOPEN",               "reopen");
define("PG_EVT_RETURN",               "return");
define("PG_EVT_REVERT",               "revert");
define("PG_EVT_SET_BAD",              "set_bad");
define("PG_EVT_CLEAR_BAD",            "clear_bad");
define("PG_EVT_CHECK_OUT",            "check_out");
define("PG_EVT_DEACTIVATE",           "deactivate");
define("PG_EVT_REACTIVATE",           "reactivate");
define("PG_EVT_DELETE",               "delete");
define("PG_EVT_CLEAR_TASK",           "clear_task");
    // issue incomplete page to another proofer
define("PG_EVT_RETRIEVE",             "retrieve"); 

define("PJ_EVT_CREATE",               "create");
define("PJ_EVT_CLONE",                "clone");
define("PJ_EVT_RELEASE",              "releaseclone");
define("PJ_EVT_DEACTIVATE",           "deactivate");
define("PJ_EVT_ACTIVATE",             "activate");
define("PJ_EVT_ADVANCE",              "advance");
define("PJ_EVT_ON_HOLD",              "on_hold");
define("PJ_EVT_OFF_HOLD",             "off_hold");
define("PJ_EVT_DELETE_PAGES",         "delete_pages");
define("PJ_EVT_DELETE",               "delete");
define("PJ_EVT_SET_PM",               "set_pm");
define("PJ_EVT_COMPLETE",             "complete");
define("PJ_EVT_ADD_FILE",             "add_file");

class DpContext
{
//	private $_page_tasks;
//	private $_project;
//	private $_counts;
//    private $_tab_count;
//    private $_theme;
    private $_bb;
    private $_languages;

	public function __construct() {
//        global $dpdb;
//        $sid = session_id();
        $this->_bb = new DpPhpbb3();
	}

    public function DefaultLocale() {
        global $User;
        return $User && $User->IsLoggedIn()
            ? $User->Language()
            : "en";
    }

    public function AllLanguagesData() {
        global $_languages_array_2;
        global $_active_languages_array_2;
        if(! isset($this->_languages)) {
            $this->_languages = array();
            foreach($_active_languages_array_2 as $code2) {
                $name = $_languages_array_2[$code2];
                $this->_languages[$code2] = $name;
            }
        }
        return $this->_languages;
    }

    public function LanguageName($code) {
        $langs = $this->AllLanguagesData();
        return isset($langs[$code])
            ? $langs[$code] : "";
    }

    public function ActiveLanguages() {
        static $_langs;
        global $dpdb;

        if(! isset($_langs)) {
            $_langs = array();
            $rows = $dpdb->SqlRows("
                SELECT DISTINCT language, other_languages
                FROM projects");

            foreach($rows as $row) {
                $lang = $row["language"];
                $olangs = $row["other_languages"];
                if(! in_array($lang, $_langs)) {
                    $name = $this->LanguageName($lang);
                    if($name != "") {
                        $_langs[$lang] = $name;
                    }
                }
                $oa = preg_split("/\s+/u", $olangs);
                foreach($oa as $lang) {
                    if(! in_array($lang, $_langs)) {
                        $name = $this->LanguageName($lang);
                        if($name != "") {
                            $_langs[$lang] = $name;
                        }
                    }
                }
            }
        }
        asort($_langs);
        return $_langs;
    }

    public function ActiveLanguagesData() {
        static $_data;
        global $_languages_array_2;
        global $_active_languages_array_2;

        if(! isset($_data)) {
            $_data = array();
            foreach($_active_languages_array_2 as $key) {
                $_data[$key] = $_languages_array_2[$key];
            }
            asort($_data);
        }
        return $_data;
    }

    public function Phpbb3() {
        return $this->_bb;
    }

    public function LatestTopicPostTime($topicid) {
        if(! $topicid)
            return null;
        $bb = $this->Phpbb3();
        return $bb->LatestTopicPostTime($topicid);
    }

    public function ForumTopicReplyCount($topicid) {
        $bb = $this->Phpbb3();
        return $bb->TopicReplyCount($topicid);
    }

    public function RoundQueueCount($roundid) {
        global $dpdb;
        return $dpdb->SqlOneValue("
            SELECT COUNT(*) 
            FROM queue_defns
            WHERE round_id='$roundid'");
    }

    public function FontFaces() {
        global $font_faces;
        return $font_faces;
    }

    public function FontSizes() {
        global $font_sizes;
        return $font_sizes;
    }

    public function SiteUrl() {
        return DP_URL;
    }

    public function GoodWordsList($langcode) {
        return implode("\n", 
                _read_site_words_array("good", $langcode));
    }

    public function BadWordsList($langcode) {
        return implode("\n", 
                _read_site_words_array("bad", $langcode));
    }

    public function WriteGoodWordsList($langcode, $words) {
        $wary = list_to_unique_array($words);
        $this->WriteGoodWordsArray($langcode, $wary);
    }
    public function WriteGoodWordsArray($langcode, $w_array) {
        $this->WriteWordsArray("good", $langcode, $w_array);
    }
    private function WriteWordsArray($code, $langcode, $warray) {
        assert(is_array($warray));
        $warray = array_unique($warray);
        $warray = array_diff($warray, array(""));
        _write_site_words_array($code, $langcode, $warray);
    }

    public function WriteBadWordsList($langcode, $words) {
        $wary = list_to_unique_array($words);
        $this->WriteBadWordsArray($langcode, $wary);
    }

    public function WriteBadWordsArray($langcode, $words_array) {
        $this->WriteWordsArray("bad", $langcode, $words_array);
    }

    public function SiteLink() {
        global $site_url, $site_name;
        return "<a href='$site_url'>$site_name</a>";
    }

    public function ActivePMArray() {
        global $dpdb;
        return $dpdb->SqlValues("
            SELECT DISTINCT username
            FROM projects
            WHERE is_active != 0");
    }

    public function ActiveGenreArray() {
        global $dpdb;
        return $dpdb->SqlValues("
            SELECT DISTINCT genre
            FROM projects
            WHERE is_active != 0");
    }

    public function ActiveRoundsArray() {
        global $dpdb;
        return $dpdb->SqlValues("
            SELECT roundid
            FROM project_round_sequence
            WHERE sequence_code = 'default'
            ORDER BY sequence");
    }

    public function TransientDirectory() {
        global $transient_path;
        return $transient_path;
    }

    public function SendZipFile($path) {
        send_file($path);
    }

    public function ZipSendString($stub, $text) {
        $tofile = $stub.".zip";
        $topath 
            = build_path( $this->TransientDirectory(), $stub.".zip");
        // $to_url 
            // = build_path($this->TransientUrl(), $stub.".zip");
        $zip = new ZipArchive();
        if(($ret = $zip->open($topath, ZIPARCHIVE::CREATE)) != true)
        {
            die("zip error $ret on open $topath.");
        }
        if(! $zip->addFromString($stub.".txt", $text))
        {
            die("zip error adding $stub to $tofile.");
        }
        if(($ret = $zip->close()) != true)
        {
            die("zip error $ret on close.");
        }
        $this->SendZipFile($topath);
    }

    public function ZipSendArray($stub, $ary) {
        $zipfile = $stub.".zip";
        $zippath = build_path( $this->TransientDirectory(), $zipfile);
        @unlink($zippath);
        $zip = new ZipArchive();
        if(! ($ret = $zip->open($zippath, ZIPARCHIVE::CREATE))) {
            die("zip error $ret on open $zippath.");
        }
        foreach($ary as $path => $text) {
            $zip->addFromString($path, $text);
        }
        $zip->close();
        $this->SendZipFile($zippath);
    }

    public function ZipSendFileArray($stub, $apaths) {
        $zipfile = $stub.".zip";
        $zippath = build_path($this->TransientDirectory(), $zipfile);
        @unlink($zippath);  // in case anything from before
        $zip = new ZipArchive();
        if(! ($zip->open($zippath, ZIPARCHIVE::CREATE))){
            die("zip error on open $zippath.");
        }
        foreach($apaths as $path) {
            if(is_file($path)) {
                if(! $zip->addFile($path, basename($path))) {
                    die("zip error adding $path to $zipfile.");
                }
            }
        }
        if(! $zip->close()) {
            die("zip error on close.");
        }
        $this->SendZipFile($zippath);
    }

    public function ZipSendDirectory($stub, $path) {
        $tofile = $stub.".zip";
        $topath 
            = build_path( $this->TransientDirectory(), $stub.".zip");
        unlink($topath);
        $files = glob("$path/*") ;
        $zip = new ZipArchive();
        if(($ret = $zip->open($topath, ZIPARCHIVE::CREATE)) != true) {
            die("zip error $ret on open $topath.");
        }
        foreach($files as $file) {
            if(is_file($file)) {
                if(! $zip->addFile($file, basename($file))) {
                    die("zip error adding $stub to $tofile.");
                }
                else {
                }
            }
        }
        if(($ret = $zip->close()) != true) {
            die("zip error $ret on close.");
        }
        $this->SendZipFile($topath);
    }

    public function RoundName($roundid) {
        return RoundIdName($roundid);
    }

    public function RoundDescription($roundid) {
        return RoundIdDescription($roundid);
    }

    public function DayActivitySummary() {
        global $dpdb;
        return $dpdb->SqlRows("
            SELECT task_code, onedaycount, twodaycount
            FROM daycount2");
    }

    public function StateSummary() {
        global $dpdb;
        return $dpdb->SqlRows("
            SELECT task_code, onedaycount, twodaycount
            FROM daycount2");
    }

    public function RoundAvailableProjects($roundid, 
                                $sort = "nameofwork") {
        global $dpdb;
        
        $sql = "
        SELECT 
            p.projectid,
            nameofwork AS title,
            authorsname AS author,
            username AS pm,
            genre,
            p.language,
            CONCAT(p.language, ' ', p.other_languages) AS languages,
            SUM( CASE WHEN pp.state LIKE '%".PAGE_AVAIL."' 
                THEN 1 ELSE 0 END) AS pages_available,
            SUM(CASE WHEN pp.state LIKE '%".PAGE_TEMP."'
                        OR pp.state LIKE '%".PAGE_OUT."'
                THEN 1 ELSE 0 END) AS pages_checked_out,
            SUM( CASE WHEN pp.state LIKE '%".PAGE_SAVED."' 
                THEN 1 ELSE 0 END) AS pages_completed,
            SUM( CASE WHEN pp.state LIKE '%".PAGE_BAD."' 
                THEN 1 ELSE 0 END) AS pages_bad,
            SUM(1) AS page_count
        FROM projects AS p
        LEFT JOIN pages AS pp
            ON p.projectid = pp.projectid
        WHERE
            p.state = '{$roundid}.".PROJ_AVAILABLE."'
        GROUP BY p.projectid
        ORDER BY
                    $sort ";
        // die(PrettySql($sql));
        return $dpdb->SqlRows($sql);
    }

    public function EntryLevelRoundId() {
        return "P1";
    }

    public function ProjectsProofingCount() {
        return 0;
    }

    public function ProjectsPPCount() {
        return 0;
    }

    public function ProjectsPostedCount() {
        return 0;
    }

    public function ProjectTransitionsToday() {
        global $dpdb;
        return $dpdb->SqlRows("
            SELECT 
                details2 AS project_state,
                count(distinct projectid) AS transcount
            FROM project_events
                WHERE event_type = 'transition' 
                AND event_time >= (UNIX_TIMESTAMP() MOD 60*60*24)
                GROUP BY details2");
    }

    public function PostedProjectCount() {
        global $dpdb;
        return $dpdb->SqlOneValue("
            SELECT COUNT(*) FROM projects
            WHERE postednum IS NOT NULL");
    }

    public function UsersWithPageCount() {
        global $dpdb;
        return $dpdb->SqlOneValue("
            SELECT COUNT(DISTINCT username)
            FROM page_events");
    }


    
    // grep discovers:
    // add                  dpproject
    // delete               dpproject (deactivate)
    // replaceImage         dppage
    // replaceText          dppage
    // modifyText 
    // checkout                 dpproject
    // saveAsInProgress         dppage
    // saveAsDone               dppage
    // reopen                   dppage
    // returnToRound            dppage
    // reclaim                  dpproject (retrieve)
    // clearRound               dpproject (clear)
    // markAsBad                dppage (setBad)
    // eraseBadMark             dppage (clearBad)

    //          deactivate       
    //          retrieve         dpproject (retrieve)
    //          replace          dpproject


/*
    public function LinkForPMToUser($username) {
        $url = $this->UrlForPMToUser($username);
        return "<a target='_blank' href='{$url}'>{$username}</a>";
    }

    public function UrlForPMToUser($username) {
        global $forums_url;
        return build_path($forums_url,
                "ucp.php?i=pm&mode=compose&un={$username}");
    }
*/
    public function IsUser($username) {
        return $this->UserExists($username);
    }

    public function UserExists($username) {
        global $dpdb;
        if(empty($username))
            return false;
        return $dpdb->SqlExists("
            SELECT 1 FROM users
            WHERE username = '$username'");
    }

    public function AllPMProjects($username = null) {
        global $User, $dpdb;

        if(!$username)
            $username = $User->Username();
        return $dpdb->SqlRows("
        SELECT 
            p.projectid,
            p.nameofwork AS title,
            p.authorsname AS author,
            p.username AS pm,
            p.genre,
            p.language,
            CONCAT(p.language, ' ', p.other_languages) AS languages,
        FROM projects AS p
        WHERE
            p.username = '$username'
        ORDER BY
            p.projectid");
    }

    public function ActivePMProjects($username = null) {
        global $User, $dpdb;

        if(!$username)
            $username = $User->Username();
        return $dpdb->SqlRows("
        SELECT 
            p.projectid,
            p.nameofwork AS title,
            p.authorsname AS author,
            p.username AS pm,
            p.genre,
            p.language,
            CONCAT(p.language, ' ', p.other_languages) AS languages,
        FROM projects AS p
        WHERE
            p.username = '$username'
            AND p.state NOT IN 
                ('".PROJ_SUBMIT_PG_POSTED."',
                 '".PROJ_DELETE."')
        ORDER BY
            p.projectid");
    }

    public function LogPageEvent($page, $event_type, $note = "") {
        global $dpdb;
        global $User;
        /** @var $page DpPage */

        $username = $User->Username();
        assert($username != "");

        $dpdb->SqlExecute("
        INSERT INTO page_events
        SET event_time = UNIX_TIMESTAMP(),
            projectid  = '{$page->ProjectId()}',
            page_name  = '{$page->PageName()}',
            username   = '$username',
            task_code  = '{$page->RoundId()}',
            event_type = '$event_type',
            note       = ".SqlQuote($note));
       }

    public function LogProjectEvent(
                    $project, $event_type, $remark = "") {
        global $dpdb;
        global $User;
        /** @var $project DpProject */

        if($remark == "") {
            $n = $dpdb->SqlExecute("
            INSERT INTO project_events
            SET event_time = UNIX_TIMESTAMP(),
                projectid   = '{$project->Projectid()}',
                who         = '{$User->Username()}',
                task_code   = '{$project->RoundId()}',
                event_type  = '$event_type'");
        }
        else {
            $n = $dpdb->SqlExecute("
            INSERT INTO project_events
            SET event_time = UNIX_TIMESTAMP(),
                projectid   = '{$project->Projectid()}',
                who         = '{$User->Username()}',
                task_code   = '{$project->RoundId()}',
                event_type  = '$event_type',
                details     = '{$remark}'");
        }
        assert($n > 0);
    }

    public function NewProjectId() {
        global $dpdb;
        $yymmdd = yymmdd();
        $sql = "
            SELECT MAX(projectid) FROM projects
            WHERE projectid LIKE '{$yymmdd}%'";
        $pid = $dpdb->SqlOneValue($sql);
        if($pid == "") {
            $i = 1;
        }
        else {
            $i = intval(substr($pid, 6, 3)) + 1;
        }
        return $yymmdd . sprintf("%03d", $i);
    }

    public function ProjectIds() {
        global $dpdb;
        $ary = array();
        $pids = $dpdb->SqlRows("
            SELECT projectid FROM projects");
        foreach($pids as $pid) {
            $ary[] = $pid['projectid'];
        }
        return $ary;
    }

    public function AllProjects() {
        global $dpdb;
        
        $ret = $dpdb->SqlRows("
        SELECT 
            p.projectid,
            p.nameofwork AS title,
            p.authorsname AS author,
            p.username AS pm,
            p.genre,
            p.language,
            CONCAT(p.language, ' ', p.other_languages) AS languages,
        FROM projects AS p
        ORDER BY
            p.projectid");
        return $ret;
    }

    public function ActiveProjects() {
        global $dpdb;
        
        return $dpdb->SqlRows("
        SELECT 
            p.projectid,
            p.nameofwork AS title,
            p.authorsname AS author,
            p.username AS pm,
            p.genre,
            p.language,
            CONCAT(p.language, ' ', p.other_languages) AS languages,
        FROM projects AS p
        WHERE
            p.state NOT IN 
            ('".PROJ_SUBMIT_PG_POSTED."',
             '".PROJ_DELETE."')
        ORDER BY
            p.projectid");
    }

    public function CreateProjectThread($subject, $message) {
        return $this->_bb->CreateProjectThread($subject, $message);
    }

    private function UserEmailAddress($username) {
        global $dpdb;
        return $dpdb->SqlOneValue("
            SELECT user_email FROM phpbb3.phpbb_users
            WHERE username = '$username'");
    }

    public function SendUserEmail($username, $subject, $message) {
        $to = $this->UserEmailAddress($username);
//        $from = "dp-help@dp-test.dm.unipi.it";
        $headers = 'From: dp-help@dp-test.dm.unipi.it' . "\r\n" .
            'Reply-To: dp-help@dp-test.dm.unipi.it' . "\r\n" .
            'X-Mailer: PHP/' . phpversion();

        mail($to, $subject, $message, $headers);
    }
}

?>
